/**
 * URL方式保存文件到本地
 * @param data 文件的blob数据
 * @param name 文件名
 */
// function saveAs(data, name) {
//   const urlObject = window.URL || window.webkitURL || window;
//   const export_blob = new Blob([data]);
//   const save_link = document.createElement('a');
//   save_link.href = urlObject.createObjectURL(export_blob);
//   save_link.download = name;
//   save_link.click();
//   urlObject.revokeObjectURL(save_link.href);
// }

/**
 * 根据文件url获取文件名
 * @param url 文件url
 */
function getFileName(url) {
  const num = url.lastIndexOf('/') + 1;
  let fileName = url.substring(num);
  //把参数和文件名分割开
  fileName = decodeURI(fileName.split('?')[0]);
  return fileName;
}

/**
 * 根据文件地址下载文件
 * @param {*} sUrl
 */
export function downloadByUrl({
  url,
  target = '_blank',
  fileName,
}: {
  url: string;
  target?: '_self' | '_blank';
  fileName?: string;
}): Promise<boolean> {
  // 是否同源
  const isSameHost = new URL(url).host == location.host;
  return new Promise<boolean>((resolve, reject) => {
    if (isSameHost) {
      const link = document.createElement('a');
      link.href = url;
      link.target = target;

      if (link.download !== undefined) {
        link.download = fileName || getFileName(url);
      }

      if (document.createEvent) {
        const e = document.createEvent('MouseEvents');
        e.initEvent('click', true, true);
        link.dispatchEvent(e);
        return resolve(true);
      }

      if (url.indexOf('?') === -1) {
        url += '?download';
      }

      window.open(url, target);
      return resolve(true);
    } else {
      const canvas = document.createElement('canvas');
      const img = document.createElement('img');
      img.setAttribute('crossOrigin', 'Anonymous');
      img.src = url;
      img.onload = _ => {
        canvas.width = img.width;
        canvas.height = img.height;
        const context = canvas.getContext('2d')!;
        context.drawImage(img, 0, 0, img.width, img.height);
        // window.navigator.msSaveBlob(canvas.msToBlob(),'image.jpg');
        // saveAs(imageDataUrl, '附件');
        canvas.toBlob(blob => {
          const link = document.createElement('a');
          link.href = window.URL.createObjectURL(blob!);
          link.download = getFileName(url);
          link.click();
          URL.revokeObjectURL(link.href);
          resolve(true);
        }, 'image/jpeg');
      };
      img.onerror = e => reject(e);
    }
  });
}

//根据地址下载对应文件
export async function downloadFileWithFetch(fileUrl: string) {
  try {
    // 发起请求
    const response = await fetch(fileUrl);

    // 检查响应状态
    if (!response.ok) {
      throw new Error(`下载失败: ${response.status} ${response.statusText}`);
    }

    // 获取文件名（从响应头中提取，可选）
    const contentDisposition = response.headers.get('content-disposition');
    let fileName = 'ToDo数据.xlsx';
    if (contentDisposition && contentDisposition.includes('filename=')) {
      fileName = contentDisposition.split('filename=')[1].replace(/"/g, '');
    }

    // 转换为Blob并下载
    const blob = await response.blob();
    const url = window.URL.createObjectURL(blob);

    // 创建隐藏的a标签
    const link = document.createElement('a');
    link.href = url;
    link.setAttribute('download', fileName);
    link.style.display = 'none';

    // 添加到文档并触发点击
    document.body.appendChild(link);
    link.click();

    // 清理资源
    document.body.removeChild(link);
    window.URL.revokeObjectURL(url);
  } catch (error) {
    console.error('下载过程中出错:', error);
    alert('文件下载失败，请稍后重试');
  }
}

//分片下载文件
export const downloadByChunks = async (
  filePath: string,
  fileName: string,
  fileSize: number
) => {
  const baseUrl = import.meta.env.VITE_BASE_API_URL;
  const singleSize = 1024 * 1024 * 1; // 1MB 每片
  let startPos = 0;
  const totalChunks = Math.ceil(fileSize / singleSize);
  const chunksInfo: { start: number; end: number }[] = [];

  // 生成正确的分片范围（确保start <= end）
  while (startPos < fileSize) {
    const endPos = Math.min(startPos + singleSize - 1, fileSize - 1);
    if (endPos < startPos) {
      console.error(`无效分片范围: start=${startPos}, end=${endPos}`);
      return; // 直接终止，避免无效请求
    }
    chunksInfo.push({ start: startPos, end: endPos });
    startPos = endPos + 1; // 下一分片从当前结束位置+1开始（关键修正）
  }

  // 分片请求函数（强化响应处理）
  const fetchChunk = async (
    start: number,
    end: number,
    chunkIndex: number,
    retry = 3
  ) => {
    try {
      // console.log(`请求分片 ${chunkIndex}/${totalChunks}: ${start}-${end}`);

      // 直接使用fetch原生API（避免Axios可能的转换问题）
      const response = await fetch(
        `${baseUrl}/tools/upload/file-chunk?filePath=${encodeURIComponent(
          filePath
        )}&start=${start}&end=${end}`,
        {
          method: 'GET',
          headers: {
            Accept: 'application/octet-stream',
            // 如需认证，添加token等 headers
            // 'Authorization': `Bearer ${token}`
          },
        }
      );

      // 1. 验证HTTP状态码（关键：206是分片正常响应）
      if (!response.ok) {
        if (response.status === 416) {
          throw new Error(`分片范围无效: 服务器不支持此范围 (${start}-${end})`);
        }
        throw new Error(`HTTP错误: 状态码 ${response.status}`);
      }

      // 2. 验证响应类型和内容
      const contentType = response.headers.get('content-type') || '';
      if (
        !contentType.includes('application/octet-stream') &&
        !contentType.includes('application/blob')
      ) {
        throw new Error(`无效响应类型: 预期二进制流，实际为 ${contentType}`);
      }

      // 3. 读取流式响应为Blob（处理大文件流式传输）
      const blob = await response.blob();

      // 4. 验证分片大小（防止空数据或不完整分片）
      const expectedSize = end - start + 1;
      if (blob.size !== expectedSize) {
        console.warn(
          `分片 ${chunkIndex} 大小不匹配: 预期 ${expectedSize} bytes，实际 ${blob.size} bytes`
        );
        // 小文件允许轻微误差，大文件严格校验
        if (
          Math.abs(blob.size - expectedSize) > 1024 &&
          fileSize > 10 * 1024 * 1024
        ) {
          throw new Error(`分片数据不完整: 大小偏差超过1KB`);
        }
      }

      return { blob, index: chunkIndex }; // 保留分片序号，确保合并顺序
    } catch (error) {
      console.error(
        `分片 ${chunkIndex} 下载失败（剩余重试: ${retry - 1}）:`,
        error.message
      );
      if (retry > 0) {
        await new Promise(resolve => setTimeout(resolve, 1000 * (4 - retry))); // 指数退避等待
        return fetchChunk(start, end, chunkIndex, retry - 1);
      }
      throw new Error(`分片 ${chunkIndex} 最终失败: ${error.message}`);
    }
  };

  try {
    // 并发控制（每次5个分片）
    const results: { blob: Blob; index: number }[] = [];
    for (let i = 0; i < chunksInfo.length; i += 5) {
      const batch = chunksInfo.slice(i, i + 5);
      const batchPromises = batch.map(({ start, end }, idx) =>
        fetchChunk(start, end, i + idx + 1)
      );
      results.push(...(await Promise.all(batchPromises)));
    }

    // 按分片序号排序（确保合并顺序绝对正确）
    results.sort((a, b) => a.index - b.index);

    // 合并分片（指定正确的MIME类型）
    const mimeType = getMimeType(fileName); // 辅助函数：根据文件名推断MIME类型
    const mergedBlob = new Blob(
      results.map(item => item.blob),
      { type: mimeType || 'application/octet-stream' }
    );

    // 验证合并后总大小
    if (mergedBlob.size !== fileSize) {
      console.warn(
        `文件大小不匹配: 预期 ${fileSize} bytes，实际 ${mergedBlob.size} bytes`
      );
      // 可选：提示用户文件可能损坏
    }

    // 触发下载
    const downloadUrl = URL.createObjectURL(mergedBlob);
    const link = document.createElement('a');
    link.href = downloadUrl;
    link.download = fileName;
    document.body.appendChild(link);
    link.click();

    // 清理资源
    setTimeout(() => {
      document.body.removeChild(link);
      URL.revokeObjectURL(downloadUrl);
    }, 1000); // 延长清理时间，避免某些浏览器下载中断
  } catch (error) {
    console.error('下载失败:', error);
    // 显示用户友好的错误提示
    alert(`下载失败: ${error.message}\n请检查网络或稍后重试`);
  }
};

// 辅助函数：根据文件名推断MIME类型
function getMimeType(fileName: string): string | null {
  const ext = fileName.split('.').pop()?.toLowerCase();
  const mimeMap: Record<string, string> = {
    png: 'image/png',
    jpg: 'image/jpeg',
    jpeg: 'image/jpeg',
    pdf: 'application/pdf',
    zip: 'application/zip',
    txt: 'text/plain',
    // 可扩展更多类型
  };
  return mimeMap[ext] || null;
}
